/*
 * brin_tuple.h
 *		处理 BRIN 特定元组的声明。
 *
 * Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group
 * Portions Copyright (c) 1994, Regents of the University of California
 *
 * IDENTIFICATION
 *	  src/include/access/brin_tuple.h
 */
#ifndef BRIN_TUPLE_H
#define BRIN_TUPLE_H

#include "access/brin_internal.h"
#include "access/tupdesc.h"

/*
 * BRIN 运算类可以注册序列化回调，以防磁盘和内存中的
 * 表现形式不同（例如出于性能原因）。
 */
typedef void (*brin_serialize_callback_type) (BrinDesc *bdesc, Datum src, Datum *dst);

/*
 * BRIN 索引每个页面范围存储一个索引元组。每个索引元组
 * 对于每个索引列都有一个 BrinValues 结构；反过来，每个 BrinValues
 * 除了 null 标志外，还有一个大小由运算类决定的 Datum 数组。
 */
typedef struct BrinValues
{
	AttrNumber	bv_attno;		/* 索引属性编号 */
	bool		bv_hasnulls;	/* 页面范围内是否有 null？ */
	bool		bv_allnulls;	/* 页面范围内所有值是否为 null？ */
	Datum	   *bv_values;		/* 当前累积值 */
	Datum		bv_mem_value;	/* 扩展的累积值 */
	MemoryContext bv_context;
	brin_serialize_callback_type bv_serialize;
} BrinValues;

/*
 * 该结构用于表示内存中的索引元组。值只能
 * 通过适当的 BrinDesc 有意义地解码。
 */
typedef struct BrinMemTuple
{
	bool		bt_placeholder; /* 这是一个占位符元组 */
	bool		bt_empty_range;	/* 范围表示没有元组 */
	BlockNumber bt_blkno;		/* 元组对应的 heap blkno */
	MemoryContext bt_context;	/* memcxt 持有 bt_columns 值 */
	/* brin_deform_tuple 的输出数组: */
	Datum	   *bt_values;		/* 值数组 */
	bool	   *bt_allnulls;	/* 全为 null 数组 */
	bool	   *bt_hasnulls;	/* 包含 null 的数组 */
	/* 不是输出数组，但必须是最后一个 */
	BrinValues	bt_columns[FLEXIBLE_ARRAY_MEMBER];
} BrinMemTuple;

/*
 * 一个磁盘上的 BRIN 元组。此后可能跟着一个 null 位掩码，
 * 为每个索引列提供 2 个 null 位的空间；后面跟着每列的
 * 一个由 opclass 定义的 Datum 值的数量。
 */
typedef struct BrinTuple
{
	/* 元组对应的 heap 块编号 */
	BlockNumber bt_blkno;

	/* ---------------
	 * bt_info 的布局如下：
	 *
	 * 第 7 位（高位）：有 null
	 * 第 6 位：是占位符元组
	 * 第 5 位：范围为空
	 * 第 4-0 位：数据的偏移量
	 * ---------------
	 */
	uint8		bt_info;
} BrinTuple;

#define SizeOfBrinTuple (offsetof(BrinTuple, bt_info) + sizeof(uint8))

/*
 * bt_info 操作宏
 */
#define BRIN_OFFSET_MASK		0x1F
#define BRIN_EMPTY_RANGE_MASK	0x20
#define BRIN_PLACEHOLDER_MASK	0x40
#define BRIN_NULLS_MASK			0x80

#define BrinTupleDataOffset(tup)	((Size) (((BrinTuple *) (tup))->bt_info & BRIN_OFFSET_MASK))
#define BrinTupleHasNulls(tup)	(((((BrinTuple *) (tup))->bt_info & BRIN_NULLS_MASK)) != 0)
#define BrinTupleIsPlaceholder(tup) (((((BrinTuple *) (tup))->bt_info & BRIN_PLACEHOLDER_MASK)) != 0)
#define BrinTupleIsEmptyRange(tup) (((((BrinTuple *) (tup))->bt_info & BRIN_EMPTY_RANGE_MASK)) != 0)


extern BrinTuple *brin_form_tuple(BrinDesc *brdesc, BlockNumber blkno,
								  BrinMemTuple *tuple, Size *size);
extern BrinTuple *brin_form_placeholder_tuple(BrinDesc *brdesc,
											  BlockNumber blkno, Size *size);
extern void brin_free_tuple(BrinTuple *tuple);
extern BrinTuple *brin_copy_tuple(BrinTuple *tuple, Size len,
								  BrinTuple *dest, Size *destsz);
extern bool brin_tuples_equal(const BrinTuple *a, Size alen,
							  const BrinTuple *b, Size blen);

extern BrinMemTuple *brin_new_memtuple(BrinDesc *brdesc);
extern BrinMemTuple *brin_memtuple_initialize(BrinMemTuple *dtuple,
											  BrinDesc *brdesc);
extern BrinMemTuple *brin_deform_tuple(BrinDesc *brdesc,
									   BrinTuple *tuple, BrinMemTuple *dMemtuple);

#endif							/* BRIN_TUPLE_H */
